package ua.edu.nuos.jeetraining2012.cms.util.template.material;

import ua.edu.nuos.jeetraining2012.cms.dto.HomeWorkDTO;
import ua.edu.nuos.jeetraining2012.cms.entity.CourseEntity;
import ua.edu.nuos.jeetraining2012.cms.entity.CourseMaterialEntity;
import ua.edu.nuos.jeetraining2012.cms.entity.UserEntity;
import ua.edu.nuos.jeetraining2012.cms.service.Course;
import ua.edu.nuos.jeetraining2012.cms.service.HomeWork;
import ua.edu.nuos.jeetraining2012.cms.service.Material;
import ua.edu.nuos.jeetraining2012.cms.service.exception.ServiceException;
import ua.edu.nuos.jeetraining2012.cms.util.LocaleWrapper;
import ua.edu.nuos.jeetraining2012.cms.util.template.layout.DefaultLayoutTemplate;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.*;

/**
 * DefaultMaterialTemplate.
 * <p/>
 * Define common material template class. All common fields & methods are presented here.
 *
 * @author Victor N. Ganichev victor.ganichev@gmail.com
 * @version 1.0 Date: 07.06.13 Time: 22:25
 * @since 1.0
 */
public class DefaultMaterialTemplate extends DefaultLayoutTemplate {

    /**
     * Define course ID.
     */
    protected Long courseId;

    /**
     * Define course title.
     */
    protected String courseTitle;

    /**
     * Define course start date.
     */
    protected Date courseStartDate;

    /**
     * Define course finish date.
     */
    protected Date courseFinishDate;

    /**
     * Define course syllabus link.
     */
    protected String syllabusLink;

    /**
     * Define course description.
     */
    protected String courseDescription;

    /** Define trigger of students enrollment to course. */
    protected boolean isEnrolled;

    /** Define trigger of students enrollment to course. */
    protected boolean isPending;

    /** Define service layer for course. */
    protected Course courseService;

    /**
     * Define material titles.
     */
    protected List<CourseMaterialEntity> materialTitles;

    /**
     * Define material service.
     */
    protected Material materialService;

    /**
     * Define course logo URL.
     */
    protected String courseLogo;

    /** Course brief description. */
    protected String courseShortDesc;

    protected HomeWork homeWorkService;

    /** List of all HW for this course. */
    protected List<HomeWorkDTO> hwList;

    /** Define User's SVN link. */
    protected String svnLink;

    // Constructors
    public DefaultMaterialTemplate() {
        logger.debug("DefaultMaterialTemplate invocation.");
        try {
            logger.debug("Trying to inject service class");
            InitialContext ic = new InitialContext();
            materialService = (Material) ic.lookup("java:module/Material");
            logger.debug("Material service injected: {}", materialService);
            homeWorkService = (HomeWork) ic.lookup("java:module/HomeWork");
            logger.debug("Homework service injected: {}", homeWorkService);
            courseService = (Course) ic.lookup("java:module/Course");
            logger.debug("Course service injected: {}", courseService);
        } catch (NamingException e) {
            logger.error("Can't get instance of InitialContext. Got NamingException with message {} and \nTrace:\n {}",
                    e.getMessage(), Arrays.deepToString(e.getStackTrace()));
        }
    }

    // Getters & Setters
    public Long getCourseId() {
        return courseId;
    }

    public void setCourseId(Long courseId) {
        this.courseId = courseId;
    }

    public String getCourseTitle() {
        return courseTitle;
    }

    public void setCourseTitle(String courseTitle) {
        this.courseTitle = courseTitle;
    }

    public Date getCourseStartDate() {
        return courseStartDate;
    }

    public void setCourseStartDate(Date courseStartDate) {
        this.courseStartDate = courseStartDate;
    }

    public Date getCourseFinishDate() {
        return courseFinishDate;
    }

    public void setCourseFinishDate(Date courseFinishDate) {
        this.courseFinishDate = courseFinishDate;
    }

    public String getSyllabusLink() {
        return syllabusLink;
    }

    public void setSyllabusLink(String syllabusLink) {
        this.syllabusLink = syllabusLink;
    }

    public String getCourseDescription() {
        return courseDescription;
    }

    public void setCourseDescription(String courseDescription) {
        this.courseDescription = courseDescription;
    }

    public List<CourseMaterialEntity> getMaterialTitles() {
        return materialTitles;
    }

    public void setMaterialTitles(List<CourseMaterialEntity> materialTitles) {
        this.materialTitles = materialTitles;
    }

    public String getCourseLogo() {
        return courseLogo;
    }

    public void setCourseLogo(String courseLogo) {
        this.courseLogo = courseLogo;
    }

    public String getCourseShortDesc() {
        return courseShortDesc;
    }

    public void setCourseShortDesc(String courseShortDesc) {
        this.courseShortDesc = courseShortDesc;
    }

    public List<HomeWorkDTO> getHwList() {
        return hwList;
    }

    public void setHwList(List<HomeWorkDTO> hwList) {
        this.hwList = hwList;
    }

    public boolean isEnrolled() {
        return isEnrolled;
    }

    public void setEnrolled(boolean enrolled) {
        isEnrolled = enrolled;
    }

    public String getSvnLink() {
        return svnLink;
    }

    public void setSvnLink(String svnLink) {
        this.svnLink = svnLink;
    }

    public boolean isPending() {
        return isPending;
    }

    public void setPending(boolean pending) {
        isPending = pending;
    }

    /**
     * Retrieve material section & sub-section titles.
     */
    protected void fetchCourseTitles() {
        logger.debug("fetchCourseTitles() - started.");

        List<CourseMaterialEntity> materialTitles = null;
        try {
            logger.debug("Retrieve material titles for course with Id {}", courseId);
            materialTitles = materialService.getTitles(courseId);
            logger.debug("Material titles: {} ", materialTitles);
            if (materialTitles == null) {
                logger.debug("Material titles is null. Building empty List.");
                materialTitles = new ArrayList<>(1);
            }
        } catch (ServiceException e) {
            logger.error("Can't retrieve titles. Error message: {}, \nTrace:\n {}", e.getMessage(),
                    Arrays.deepToString(e.getStackTrace()));
            logger.debug("indexAction() catch ServiceException. Creating empty values.");
            materialTitles = new ArrayList<>(1);
        }

        setMaterialTitles(materialTitles);
        logger.debug("fetchCourseTitles - finished.");
    }

    /**
     * Retrieve course titles, start & finish dates.
     */
    protected void fetchCourseInfo() {
        logger.debug("fetchCourseInfo() - started.");

        CourseEntity courseInfo = null;
        try {
            logger.debug("Retrieving course info.");
            courseInfo = materialService.getCourseDescription(courseId);
            logger.debug("CourseInfo: {}", courseInfo);
        } catch (ServiceException e) {
            logger.error("Can't retrieve course information. Error Message: {}, \nTrace:\n {}", e.getMessage(),
                    Arrays.deepToString(e.getStackTrace()));
            logger.debug("fetchCourseInfo() caught ServiceException. Creating default values.");
            courseInfo = new CourseEntity();
            courseInfo.setTitle("No title");
            courseInfo.setDescription("Description");
            courseInfo.setStartDate(new java.util.Date());
            courseInfo.setFinishDate(new java.util.Date());
            courseInfo.setSyllabusLink("http://example.com/syllabus.pdf");
            courseInfo.setLogoURL("http://placehold.it/300x220");
            courseInfo.setShortDescription("");
        }

        setCourseTitle(courseInfo.getTitle());
        setCourseDescription(courseInfo.getDescription());
        setCourseStartDate(courseInfo.getStartDate());
        setCourseFinishDate(courseInfo.getFinishDate());
        setSyllabusLink(courseInfo.getSyllabusLink());
        setCourseLogo(courseInfo.getLogoURL());
        setCourseShortDesc(courseInfo.getShortDescription());
        setHwList(homeWorkService.getAllHomeworkByCourse(courseId));

        if (subject != null && subject.isAuthenticated()) {
            UserEntity user = (UserEntity) subject.getSession().getAttribute("user");
            if (user != null && courseInfo.getId() > 0l) {
                setEnrolled(courseService.isEnrolledToThisCourse(user.getId(), courseInfo.getId()));
                setPending(courseService.isPendingEnrollment(user.getId(), courseInfo.getId()));
            }
        }

        logger.debug("fetchCourseInfo() - finished");
    }

    /**
     * Define i18n for materials.
     *
     * @param parentI18nMap         Parent i18n map.
     * @return                      Augmented i18n Map.
     */
    protected Map<String,Object> getI18nMap(Map<String, Object> parentI18nMap) {
        logger.debug("getI18nMap() - started.");
        logger.debug("parent i18n Map is {}", parentI18nMap);

        ResourceBundle i18n = LocaleWrapper.getBundle("material", locale);
        ResourceBundle i18nCourse = LocaleWrapper.getBundle("course", locale);

        Map<String, Object> i18nCourseMap = new HashMap<>();
        i18nCourseMap.put("enroll_button_label", i18nCourse.getString("enroll-button-label"));
        i18nCourseMap.put("pending_label", i18nCourse.getString("pending_label"));
        i18nCourseMap.put("svn_header", i18nCourse.getString("svn_header"));
        i18nCourseMap.put("svn_credits_title", i18nCourse.getString("svn_credits_title"));
        i18nCourseMap.put("svn_intro_text", i18nCourse.getString("svn_intro_text"));
        i18nCourseMap.put("svn_passwd", i18nCourse.getString("svn_passwd"));


        Map<String, Object> i18nMapMaterial = new HashMap<>();
        i18nMapMaterial.put("syllabus", i18n.getString("syllabus"));
        i18nMapMaterial.put("courseHome", i18n.getString("courseHome"));
        i18nMapMaterial.put("slide", i18n.getString("slide"));
        i18nMapMaterial.put("sidebarHeader", i18n.getString("sidebarHeader"));
        i18nMapMaterial.put("noMaterialFoundTitle", i18n.getString("noMaterialFoundTitle"));
        i18nMapMaterial.put("noMaterialFoundBody", i18n.getString("noMaterialFoundBody"));
        i18nMapMaterial.put("homework_a_label", i18n.getString("homework_a_label"));
        i18nMapMaterial.put("homework_expire_text", i18n.getString("homework_expire_text"));
        i18nMapMaterial.put("svn_a_label", i18n.getString("svn_a_label"));


        Map<String, Object> i18nMap = (parentI18nMap == null)
                ? new HashMap<String, Object>()
                : parentI18nMap;

        i18nMap.put("material", i18nMapMaterial);
        i18nMap.put("courses", i18nCourseMap);

        logger.debug("getI18nMap() - finished");
        return i18nMap;
    }
}
